package com.sangmo.fts.process.receivable.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.data.filter.NativeQueryBuilder;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.data.filter.ValueFilter;
import com.sangmo.boot.framework.plugin.dataview.crud.service.DelegateViewService;
import com.sangmo.boot.framework.plugin.dataview.crud.service.ViewService;
import com.sangmo.boot.framework.plugin.dataview.spi.jpa.NativeQueryBuilderFactory;
import com.sangmo.fts.basic.model.Goods;
import com.sangmo.fts.basic.service.GoodsService;
import com.sangmo.fts.common.authority.AuthorityFilterChain;
import com.sangmo.fts.common.authority.Rights;
import com.sangmo.fts.common.authority.sql.WhereModifier;
import com.sangmo.fts.process.receivable.model.RpfContract;
import com.sangmo.fts.process.receivable.model.RpfContractItem;
import com.sangmo.fts.process.receivable.model.RpfLoan;
import com.sangmo.fts.process.storage.model.CsfContract;
import com.sangmo.fts.process.storage.model.CsfContractItem;
import javafx.print.Collation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class RpfContractService extends DelegateViewService<RpfContract> {

    @Autowired
    private RpfContractEntityService rpfContractEntityService;

    @Autowired
    private RpfContractItemEntityService rpfContractItemEntityService;

    @Autowired
    private GoodsService goodsService;

    @Override
    protected ViewService<RpfContract> getEntityService() {
        return rpfContractEntityService;
    }

    public void buyerConfirm(Long id) {
        RpfContract contract = this.get(id);
        if (null == contract.getBuyerConfirmDoc()) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.buyerConfirm.permit.disabled");
        }
        if (contract.isBuyerConfirm()) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.buyerConfirm.state.wrong");
        }
        rpfContractEntityService.buyerConfirm(contract);
    }

    public void sellerConfirm(Long id) {
        RpfContract contract = this.get(id);
        if (null == contract.getSellerConfirmDoc()) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.sellerConfirm.permit.disabled");
        }
        if (contract.isSellerConfirm()) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.sellerConfirm.state.wrong");
        }
        rpfContractEntityService.sellerConfirm(contract);
    }

    public List<RpfContractItem> listItemsByContractId(Long contractId) {
        return rpfContractItemEntityService.findByContractId(contractId);
    }

    public BigDecimal calculateContractAmount(Long id) {
        RpfContract contract = this.get(id);
        List<RpfContractItem> contractItems = rpfContractItemEntityService.findByContractId(contract.getId());
        BigDecimal contractAmount = BigDecimal.ZERO;
        Map<Long, Goods> goodsMap = goodsService.getAllGoodsMapCache();
        for (RpfContractItem item : contractItems) {
            Goods goods = goodsMap.get(item.getGoodsId());
            if (null == goods) {
                throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.goods.amount.wrong");
            }
            contractAmount = contractAmount.add(goods.getPrice().multiply(item.getQuantity()));
        }
        return contractAmount;
    }

    public PageResult<RpfContract> waybillSelection(PageSearch ps) {
        WhereModifier modifier = AuthorityFilterChain.getInstance().createNativeModifier("a", RpfContract.class, Rights.READ);
        ps.getFilters().add(new ValueFilter("buyerConfirm", ValueFilter.OP_EQ, true));
        ps.getFilters().add(new ValueFilter("sellerConfirm", ValueFilter.OP_EQ, true));
        NativeQueryBuilder builder = NativeQueryBuilderFactory.create()
                .putAlias("a", RpfContract.class)
                .selectForm("SELECT a.* FROM rpf_contract a ")
                .where("NOT EXISTS (select 1 from rpf_waybill rw where rw.contract_id = a.id and rw.deleted = 0) ")
                .where(ps)
                .where(modifier.getSql()).putVariables(modifier.getVariables())
                .transform(RpfContract.class);
        return builder.buildPage();
    }

    public PageResult<RpfContract> loanSelection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("buyerConfirm", ValueFilter.OP_EQ, true));
        ps.getFilters().add(new ValueFilter("sellerConfirm", ValueFilter.OP_EQ, true));
        NativeQueryBuilder builder = NativeQueryBuilderFactory.create()
                .putAlias("a", RpfContract.class)
                .selectForm("SELECT a.* FROM rpf_contract a ")
                .where("EXISTS (select 1 from rpf_waybill rw where rw.contract_id = a.id and rw.deleted = 0) ")
                .where(ps)
                .transform(RpfContract.class);
        return builder.buildPage();
    }

//    public RpfContract checkByLoanSelection(Long trainingId, Long contractId) {
//
//
//    }

    public RpfContract checkAndGet(Long trainingId, Long contractId) {
        NativeQueryBuilder builder = NativeQueryBuilderFactory.create()
                .putAlias("a", RpfContract.class)
                .selectForm("SELECT a.* FROM rpf_contract a ")
                .where(" a.training_id = :trainingId")
                .where(" a.id = :contractId")
                .where("NOT EXISTS (select 1 from rpf_waybill rw where rw.contract_id = a.id and rw.deleted = 0) ")
                .putVariable("trainingId", trainingId)
                .putVariable("contractId", contractId)
                .transform(RpfContract.class);
        List<RpfContract>  contractList =  (List<RpfContract>) builder.build();
        if (contractList.size() != 1) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfContract.not.available");
        }
        return contractList.get(0);
    }

}
